package jmetal.metaheuristics.dnsgaii;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.logging.FileHandler;
import java.util.logging.Logger;

import jmetal.core.Algorithm;
import jmetal.core.Operator;
import jmetal.core.Problem;
import jmetal.core.SolutionSet;
import jmetal.operators.crossover.CrossoverFactory;
import jmetal.operators.mutation.MutationFactory;
import jmetal.operators.selection.SelectionFactory;
import jmetal.util.HvIndicator;
import jmetal.util.JMException;
import jmetal.util.MathUtil;


public class Exp_WFG {
	public static Logger logger_; // Logger object
	public static FileHandler fileHandler_; // FileHandler object

	/**
	 * @param args
	 *            Command line arguments.
	 * @throws JMException
	 * @throws IOException
	 * @throws SecurityException
	 *             Usage: three options -
	 *             jmetal.metaheuristics.nsgaII.NSGAII_main -
	 *             jmetal.metaheuristics.nsgaII.NSGAII_main problemName -
	 *             jmetal.metaheuristics.nsgaII.NSGAII_main problemName
	 *             paretoFrontFile
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void main(String[] args)
			throws JMException, SecurityException, IOException, ClassNotFoundException, NoSuchMethodException,
			InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Problem problem; // The problem to solve
		Algorithm algorithm; // The algorithm to use
		Operator crossover; // Crossover operator
		Operator mutation; // Mutation operator
		Operator selection; // Selection operator

		HashMap parameters; // Operator parameters

		HvIndicator indicators; // Object to get quality indicators

		indicators = null;
		String outDirect = "";

		String[] probName = { "jmetal.problems.WFG.WFG1", "jmetal.problems.WFG.WFG2", "jmetal.problems.WFG.WFG3",
				"jmetal.problems.WFG.WFG4", "jmetal.problems.WFG.WFG5", "jmetal.problems.WFG.WFG6",
				"jmetal.problems.WFG.WFG7", "jmetal.problems.WFG.WFG8","jmetal.problems.WFG.WFG9"};
		
		Integer[] popuSize = { 0, 0, 0, 120, 286, 126, 182, 0, 156, 0, 276 };// 种群数量
		Integer[] dimension = { 3, 5, 8,10 };//目标数
		
		for (int dimNum = 1; dimNum < 2; dimNum++) {
			for (int probNum = 4; probNum < 6; probNum++) {
				Class<?> wfg = Class.forName(probName[probNum]);
				Constructor<?> constr = wfg.getConstructor(String.class, Integer.class, Integer.class,Integer.class);
				problem = (Problem) constr.newInstance("Real", 2*(dimension[dimNum]-1), 20,dimension[dimNum]);

				indicators = new HvIndicator(problem);
				
				/**
				 * 1、修改文件名 2、选择算子
				 */
				outDirect = "output_data/dnsga2/" + problem.getName() + "/";

				algorithm = new DNSGAII(problem);

				// Algorithm parameters
				int maxGene = 1001;
				
				algorithm.setInputParameter("populationSize", popuSize[problem.getNumberOfObjectives()]);
				algorithm.setInputParameter("maxEvaluations", popuSize[problem.getNumberOfObjectives()] * maxGene);

				// Mutation and Crossover for Real codification
				parameters = new HashMap();
				parameters.put("probability", 1.0);
				parameters.put("distributionIndex", 30.0);
				crossover = CrossoverFactory.getCrossoverOperator("SBXCrossover", parameters);

				parameters = new HashMap();
				parameters.put("probability", 1.0 / problem.getNumberOfVariables());
				parameters.put("distributionIndex", 20.0);
				mutation = MutationFactory.getMutationOperator("PolynomialMutation", parameters);

				// Selection Operator
				parameters = null;
				selection = SelectionFactory.getSelectionOperator("BinaryTournamentDirFitness", parameters);

				// Add the operators to the algorithm
				algorithm.addOperator("crossover", crossover);
				algorithm.addOperator("mutation", mutation);
				algorithm.addOperator("selection", selection);

				// if it is WFG this will be true
				algorithm.setInputParameter("normalization", true);
				
				int run = 30;
				String path = outDirect+problem.getNumberOfObjectives()+"D_hv"+".dat";
				FileOutputStream output = new FileOutputStream(new File(path));
				
				double[] hvs = new double[run];
				for (int i = 0; i < run; i++) {
					System.out.println(problem.getName()+"_"+problem.getNumberOfObjectives()+"D_RUN_"+i);
					// Execute the Algorithm
					long initTime = System.currentTimeMillis();
					SolutionSet population = algorithm.execute();
					long estimatedTime = System.currentTimeMillis() - initTime;

					// Result messages
					System.out.println("Total execution time: " + estimatedTime + "ms");
					System.out.println("Write to "+outDirect + "FUN_" + problem.getNumberOfObjectives() + "D_" + i);
					population.printObjectivesToFile(outDirect + "FUN_" + problem.getNumberOfObjectives() + "D_" + i);
					double hv = indicators.getHyperVolume(population);
					hvs[i] = hv;
					String indic = "Run_"+i+":\t"+hv+"\t"+estimatedTime+"\n";
					System.out.println(indic);
					output.write(indic.getBytes());
				}
				DecimalFormat aveF= new DecimalFormat("0.0000E00");
				DecimalFormat stdF = new DecimalFormat("0.00E00");
				double ave = MathUtil.getAvarage(hvs);
				double std = MathUtil.getStd(hvs);
				output.write(("ave"+": \t"+aveF.format(ave)+"\n").getBytes());
				output.write(("std"+": \t"+stdF.format(std)+"\n").getBytes());
				output.close();
				
			}
		}
	} // main
}
